import { AnimationFrame } from '../animation/animation-frame';


/**
 * 时间节点对象
 * @param id 节点对象id
 * @param time 时间（秒）
 * @param callback 回调函数
 * @param called 当前周期中是否已被调用
 */
interface ITimerDurationHandle {
    id: number,
    time: number,
    callback: { (): void },
    called: boolean,
}

/**
 * 时间间隔对象
 * @param id 间隔对象id
 * @param callback 回调函数
 */
interface ITimerIntervalHandle {
    id: number,
    callback: { (): void },
}


/**
 * 时间节点管理
 */
class Timer {

    private static _timeStart = 0;
    private static _timeEnd = 0;
    private static _started = false;
    private static _paused = false;
    private static _durationHandles: Array<ITimerDurationHandle> = [];
    private static _intervalHandles: Array<ITimerIntervalHandle> = [];
    private static _count = 0;
    private static _timeLast = 0;
    private static _dta = 0;
    private static _req = {};

    /**
     * 节点检测间隔时长（秒）
     */
    public static intervalInSeconds: number = 1;

    /**
     * 当前周期累计时长
     */
    public static get duration(): number {
        return this._dta;
    }

    /**
     * 添加时间节点对象
     * @param timeInSeconds 在当前周期中的节点时刻（秒）
     * @param callback 在到达节点时刻需要执行的回调函数
     * @returns 时间节点对象
     */
    public static addDurationHandle(timeInSeconds: number, callback: { (): void }): ITimerDurationHandle | null {
        const handle = {
            id: this._count++,
            time: timeInSeconds,
            callback: callback,
            called: false,
        };
        this._durationHandles.push(handle);
        return handle;
    }

    /**
     * 添加时间间隔对象
     * @param callback 每次时间间隔需要执行的回调函数
     * @returns 时间间隔对象
     */
    public static addIntervalHandle(callback: { (): void }): ITimerIntervalHandle | null {
        const handle = {
            id: this._count++,
            callback: callback,
        };
        this._intervalHandles.push(handle);
        return handle;
    }

    /**
     * 移除时间节点对象或间隔对象
     * @param handle 时间节点对象或间隔对象，或其id
     */
    public static removeHandle(handle: number | ITimerDurationHandle | ITimerIntervalHandle): void {
        const isId = typeof handle === 'number';
        let idx = -1;
        for (let i = 0; i < this._durationHandles.length; i++) {
            const h = this._durationHandles[i];
            if (isId ? (handle === h.id) : (handle.id === h.id)) {
                idx = i;
                break;
            }
        }
        if (idx > -1) {
            this._durationHandles.splice(idx, 1);
            return;
        }
        for (let i = 0; i < this._intervalHandles.length; i++) {
            const h = this._intervalHandles[i];
            if (isId ? (handle === h.id) : (handle.id === h.id)) {
                idx = i;
                break;
            }
        }
        if (idx > -1) {
            this._intervalHandles.splice(idx, 1);
        }
    }

    /**
     * 开始计时周期
     */
    public static start(): void {
        this._dta = 0;
        this._timeStart = performance.now();
        this._timeLast = this._timeStart;
        this._durationHandles.forEach(handle => handle.called = false);
        if (this._started) return;
        this._started = true;
        AnimationFrame.request(() => {
            Timer.checkPoint();
        }, this.intervalInSeconds * 1000, this.intervalInSeconds * 1000 + 100, this._req);
    }

    /**
     * 暂停累加计时
     */
    public static set pause(pause: boolean) {
        this._paused = pause;
    }

    public static get pause(): boolean {
        return this._paused;
    }

    /**
     * 检查时间点（累加计时）
     */
    private static checkPoint(): void {
        this._timeEnd = performance.now();

        if (this._paused) {
            let dt = this._timeEnd - this._timeLast;
            this._timeStart += dt;
        }

        this._dta = (this._timeEnd - this._timeStart) * 0.001;
        for (const handle of this._durationHandles) {
            if (handle.time > this._dta) continue;
            if (handle.called) continue;
            handle.callback();
            handle.called = true;
        }
        this._intervalHandles.forEach(handle => handle.callback());
        this._timeLast = this._timeEnd;
    }

}


export { Timer };
export type { ITimerDurationHandle, ITimerIntervalHandle };